package name.sraynal.coodiary.fileprovider.handler;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ConfigHandler extends DefaultHandler {

	private List<File> files;	
	private StringBuffer buffer;
	private boolean isIncludeTag;
	private Set<String> includedTypes;
	private File currentDir;
	private Mapping currentMapping;
	private Map<String, String> typeMappings;
	private List<File> wholeDirs;
	private boolean isWholeDir;
	
	public Map<String, String> getTypeMappings() {
		return typeMappings;
	}

	@Override
	public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
		// TODO Auto-generated method stub
		super.characters(arg0, arg1, arg2);
		this.buffer.append(arg0, arg1, arg2);
	}

	@Override
	public void endElement(String arg0, String arg1, String qName)
			throws SAXException {
		super.endElement(arg0, arg1, qName);

		if ("fileset".equals(qName)) {

		} else if ("dirloc".equals(qName)) {
			this.currentDir = new File(buffer.toString().trim());
			if (this.isWholeDir) {
				this.wholeDirs.add(this.currentDir);
			}
		} else if ("filename".equals(qName)) {
			if (!this.isWholeDir) {
				this.files.add(new File(this.currentDir, buffer.toString().trim()));
			}
		} else if ("type-mappings".equals(qName)) {
		} else if ("mapping".equals(qName)) {
			for (int i = 0;i < this.currentMapping.getAbbrs().size(); i++) {
				this.typeMappings.put(this.currentMapping.getAbbrs().get(i), this.currentMapping.getTypeName());
			}
		} else if ("typename".equals(qName)) {
			this.currentMapping.setTypeName(this.buffer.toString());
		} else if ("abbr".equals(qName)) {
			if (this.currentMapping.getAbbrs() == null) {
				this.currentMapping.setAbbrs(new ArrayList<String>());
			}
			this.currentMapping.getAbbrs().add(this.buffer.toString());
		} else if ("type".equals(qName) && isIncludeTag) {
			this.includedTypes.add(this.buffer.toString());
		} else if ("include-only".equals(qName)) {
			this.isIncludeTag = false;
		}
	}

	@Override
	public void startDocument() throws SAXException {
		super.startDocument();
		this.files = new ArrayList<File>();
		this.buffer = new StringBuffer();
		this.typeMappings = new HashMap<String, String>();
		this.includedTypes = new HashSet<String>();
		this.isIncludeTag = false;
		this.isWholeDir = false;
		this.wholeDirs = new ArrayList<File>();
	}

	@Override
	public void startElement(String arg0, String arg1, String qName,
			Attributes attrs) throws SAXException {
		super.startElement(arg0, arg1, qName, attrs);
		
		if ("fileset".equals(qName)) {
			this.currentDir = null;
		} else if ("dirloc".equals(qName)) {
			this.buffer = new StringBuffer();
			if ((attrs.getValue("all-files") != null)
					&& ("true".equals(attrs.getValue("all-files")))) {
				this.isWholeDir = true;
			} else {
				this.isWholeDir = false;
			}
		} else if ("filename".equals(qName)) {
				this.buffer = new StringBuffer();
		} else if ("type-mappings".equals(qName)) {
			this.buffer = new StringBuffer();
		} else if ("mapping".equals(qName)) {
			this.buffer = new StringBuffer();
			this.currentMapping = new Mapping();
		} else if ("typename".equals(qName)) {
			this.buffer = new StringBuffer();
		} else if ("abbr".equals(qName)) {
			this.buffer = new StringBuffer();
		} else if ("type".equals(qName) && isIncludeTag) {
			this.buffer = new StringBuffer();
		} else if ("include-only".equals(qName)) {
			this.isIncludeTag = true;
		}
	}

	public List<File> getFiles() {
		return files;
	}
	
	public Set<String> getIncludedTypes() {
		return includedTypes;
	}

	public List<File> getWholeDirs() {
		return wholeDirs;
	}

	private class Mapping {
		private String typeName;
		private List<String> abbrs;
		public String getTypeName() {
			return typeName;
		}
		public void setTypeName(String typeName) {
			this.typeName = typeName;
		}
		public List<String> getAbbrs() {
			return abbrs;
		}
		public void setAbbrs(List<String> abbrs) {
			this.abbrs = abbrs;
		}
	}
}
